home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / Libraries / SAT 2.3b4 / Demo ƒ / SAT Invaders demo ƒ / main.p < prev    next >
Text File  |  1995-05-01  |  11KB  |  342 lines

  1. {================================================}
  2. {=============== SATInvaders main unit ================}
  3. {================================================}
  4.  
  5. { Example file for Ingemars Sprite Animation Toolkit. }
  6. { © Ingemar Ragnemalm 1992 }
  7. { See doc files for legal terms for using this code. }
  8.  
  9. { SATInvaders is a very simple game demonstrating how to use the Sprite Animation}
  10. { Toolkit. It is intended as a minimal demonstration, without many features and options}
  11. { that the other sample program, HeartQuest, has. No high scores or even score, only}
  12. { one life, doesn't save settings, only one kind of enemy, no special effects like explosions}
  13. { etc. However, it is still a full Mac application with menus and event handling (using}
  14. {TransSkel). There are now some even more "minimal" demos without that.}
  15.  
  16. program SATInvaders;
  17.  
  18.     uses
  19. {$IFC UNDEFINED THINK_PASCAL}
  20.         Types, QuickDraw, Menus, ToolUtils, Resources, {}
  21.         TransSkel, 
  22. {$ELSEC}
  23.         TransSkel, 
  24. {$ENDC}
  25.         SAT, GameGlobals, SoundConst, sPlayer, sEnemy, sShot, sMissile;
  26.  
  27.     var
  28.         soundFlag, plotFastFlag: Boolean;
  29.  
  30. { -------------------------------------------------------------------- }
  31. {                                Game driver procedures                                }
  32. { -------------------------------------------------------------------- }
  33.  
  34. { Setup a new level. This is called when the game starts and at each new level.}
  35.     procedure SetupLevel (level: integer);
  36.         var
  37.             i, j: integer;
  38.             sp: SpritePtr;
  39.     begin { SetupLevel }
  40.  
  41. { Clear the Sprite list! Note that this leaves the images "dead" on the screen,}
  42. { but we will soon erase them. }
  43.         while gSAT.sRoot <> nil do
  44.             SATKillSprite(gSAT.sRoot);
  45.  
  46.         missileCount := 0; { count variable in mMissile }
  47.  
  48. { Create all the enemy sprites for the level, depending on the level number. }
  49.         for i := 0 to (level + 1) do
  50.             for j := 0 to (level div 2) + 1 do
  51.                 sp := SATNewSprite(-3, i * 40 + 2, j * 40 - 40 * (level div 2 + 1), @SetupEnemy);
  52.  
  53. { Make the player sprite. }
  54.         sp := SATNewSprite(2, gSAT.offSizeH div 2, gSAT.offSizeV - 40, @SetupPlayer);
  55.  
  56. { Copy BackScreen to OffScreen to erase old sprites. }
  57.         CopyBits(gSAT.backScreen.port^.portbits, gSAT.offScreen.port^.portbits, gSAT.offScreen.port^.portrect, gSAT.offScreen.port^.portrect, srcCopy, nil);
  58.         SATRedraw;
  59.     end; { SetupLevel }
  60.  
  61. { Start a new game. Initialize level, score, number of lives, and call setuplevel to make the first level. }
  62.     procedure StartGame;
  63.     begin
  64.         level := 1;
  65.         SetupLevel(level);
  66.     end;
  67.  
  68. { Declare forward since we want to call it from MoveIt }
  69.     procedure DoFileMenu (item: integer);
  70.     forward;
  71.  
  72. { This routine is the game driver. It calls SATRun repeatedly until the game ends or is paused. }
  73. { I also read the keyboard here. This could optionally be moved to the "player object" module. }
  74.  
  75.     procedure MoveIt;
  76.         var
  77.             t: longint;
  78.             theEvent: EventRecord; { för att testa musklick }
  79.     begin
  80.         stillrunning := true; { A flag that tells whether or not to quit this routine. }
  81.  
  82. { Hide cursor and menu bar }
  83.  { NOTE: No matter how we leave the MoveIt procedure, we should ShowCursor. }
  84.         HideCursor;
  85.         SATHideMBar(gSAT.wind.port);
  86.         SATRedraw; {We must redraw the menu bar area. I'm lazy and redraw it all.}
  87.  
  88. { Main loop! Keep running until the game is paused or ends. }
  89.         while stillrunning = true do
  90.             begin
  91.                 t := TickCount; {Remember when we started the last turn through the loop.}
  92.  
  93. { Here is the real heart of the loop: call Animator once per loop. It will call all the objects,}
  94. { draw and erase them, sort them etc. }
  95.                 SATRun(plotFastFlag);
  96.  
  97. { All the rest of the main loop is game specific, next level, bonus handling, etc. }
  98.  
  99. {Handle the speed of the invaders. Since all move the same way, this is done globally.}
  100.                 if globalspeed.h = 0 then
  101.                     begin
  102.                         downcount := pred(downcount);
  103.                         if downcount <= 0 then
  104.                             begin
  105.                                 globalspeed.h := -lasth;
  106.                                 globalspeed.v := 0;
  107.                                 turnflag := false;
  108.                             end;
  109.                     end
  110.                 else if turnflag then
  111.                     begin
  112.                         downcount := 10;
  113.                         lasth := globalspeed.h;
  114.                         globalspeed.h := 0;
  115.                         globalspeed.v := 3;
  116.                     end;
  117.  
  118. {End of level? If so, set up a new one!}
  119.                 if not gSAT.anyMonsters then
  120.                     begin
  121.                         SATSoundShutUp;
  122.                         level := level + 1;
  123.                         SetupLevel(level);
  124.                     end; {if not anymonsters}
  125.  
  126. { Check for keys being pressed - but don't allow background processing.}
  127. { If you want background processing, either use GetNextEvent+SystemTask or WaitNextEvent (the modern call).}
  128.                 if GetOSEvent(keyDownMask, theEvent) then { keydown only }
  129.                     if BitAnd(theEvent.modifiers, cmdKey) <> 0 then {Command key pressed?}
  130.                         case char(BitAnd(theEvent.message, charCodeMask)) of {With what key?}
  131.                             'q': 
  132.                                 begin {Quit!}
  133.                                     SkelWhoa;        {Tell TransSkel to quit.}
  134. { Do all the things we have to do when we leave MoveIt! }
  135.                                     SATSoundShutUp; { Dispose of sound channel }
  136.                                     FlushEvents(EveryEvent, 0); { To forget events, like mouse clicks etc. }
  137.                                     ShowCursor;
  138.                                     SATShowMBar(gSAT.wind.port);
  139.                                     exit(MoveIt);
  140.                                 end;
  141.                             's': 
  142.                                 begin {Sound on/off}
  143.                                     DoFileMenu(sound);
  144.                                 end;
  145.                             otherwise
  146.                                 ; {Ignore others}
  147.                         end; { case}
  148.  
  149. { Delay, using TickCount so it doesn't matter how fast our Mac is. }
  150.                 while ((TickCount - t) < 3) do {3/60 per frame = 20 fps if possible}
  151.                     ;
  152.             end; { while stillrunning (main loop) }
  153.  
  154.         while not SATSoundDone do
  155.             SATSoundEvents; {Wait for last sound to complete}
  156.  
  157.         ShowCursor; {Balance HideCursor}
  158.         SATShowMBar(gSAT.wind.port);
  159.         FlushEvents(EveryEvent - DiskMask, 0); { To forget events, like mouse clicks etc. except disk events }
  160.  
  161.         SATReportStr('Sorry, game over.');
  162.  
  163.         SATSoundShutUp; { Dispose of sound channel }
  164.     end; { MoveIt }
  165.  
  166.     procedure GameWindUpdate;
  167.         var
  168.             watch: CursHandle;
  169.     begin
  170. {Set the cursor to wait cursor during screen depth change test. If there's no change,}
  171. {the user won't notice.}
  172.         watch := GetCursor(WatchCursor);
  173.         SetCursor(watch^^);
  174.         if SATDepthChangeTest then
  175.             begin
  176. {Do anything needed after a screen depth change. In this demo, nothing.}
  177.             end;
  178.         ReleaseResource(Handle(watch));
  179. {Set the cursor to arrow again.}
  180.         InitCursor;
  181.  
  182. {Process the update event by redrawing the window.}
  183.         SATRedraw;
  184.  
  185. {Note: SATRedraw can be replaced by drawing with CopyBits, i.e.:}
  186. {SATSetPortScreen;}
  187. {CopyBits(offScreen.port^.portBits, gSAT.wind.port^.portBits, offScreen.port^.portRect, offScreen.port^.portRect, srcCopy, nil);}
  188. {plus drawing borders. SATRedraw draws them black.}
  189.     end;
  190.  
  191. {    Process selection from File menu.}
  192.  
  193.     procedure DoFileMenu (item: integer);
  194.     begin
  195.         case item of
  196.             run: 
  197.                 begin
  198. { Test if we have Color QD, and if so, test bit depth! Alert if features^^.PlotFast.}
  199.                     if not ((gSAT.initDepth = 1) or (gSAT.initDepth = 4) or (gSAT.initDepth = 8)) and plotFastFlag then
  200.                         begin
  201.                             SATReportStr('Please uncheck ''Fast animation'' or set the monitor to b/w, 4-bit or 8-bit mode in the Control Panel.');
  202.                             exit(DoFileMenu);
  203.                         end;
  204.                     if SATDepthChangeTest then {Update if necessary}
  205.                         ;
  206.                     StartGame;
  207.                     ShowWindow(gSAT.wind.port);
  208.                     SelectWindow(gSAT.wind.port);
  209.                     GameWindUpdate;
  210.                     MoveIt;
  211.                 end;
  212.             sound: 
  213.                 begin
  214.                     soundFlag := not soundFlag;
  215.                     CheckItem(FileMenu, sound, soundFlag);
  216.                     if soundFlag then { Tell the sound package our settings, so we don't have to bother. }
  217.                         SATSoundOn
  218.                     else
  219.                         SATSoundOff;
  220.                 end;
  221.             fastAnimation: 
  222.                 begin
  223.                     plotFastFlag := not plotFastFlag;
  224.                     CheckItem(fileMenu, fastAnimation, plotFastFlag);
  225.                 end;
  226.             quit: 
  227.                 SkelWhoa;
  228.         end;
  229.     end;
  230.  
  231.     procedure GameWindInit;
  232.     begin
  233. { Tell TransSkel to tell us when to update SATwind. }
  234.         if SkelWindow(gSAT.wind.port, nil, nil, @GameWindUpdate, nil, nil, nil, nil, false) then
  235.             ;
  236.  
  237. {We use SATCustomInit, so we must show the window ourselves}
  238.         ShowWindow(gSAT.wind.port);
  239.         SelectWindow(gSAT.wind.port);
  240. { Draw the contents of the window (to give the user something to look at during the rest of startup). }
  241.         SATRedraw;
  242.     end;
  243.  
  244. { -------------------------------------------------------------------- }
  245. {                        Menu handling procedures                        }
  246. { -------------------------------------------------------------------- }
  247.  
  248. {    Handle selection of "About…" item from Apple menu}
  249.  
  250.     procedure DoAbout;
  251.         var
  252.             versionString: Str255;
  253.     begin
  254.         SATGetVersion(versionString);
  255.         ParamText(versionString, '', '', '');
  256.         if Alert(aboutAlrt, nil) = 1 then
  257.             ;
  258.     end;
  259.  
  260. {    Initialize menus.  Tell TransSkel to process the Apple menu}
  261. {    automatically, and associate the proper procedures with the}
  262. {    File menu.}
  263.  
  264.     procedure SetUpMenus;
  265.     begin
  266.         SkelApple('About SAT Invaders…', @DoAbout);
  267.         fileMenu := GetMenu(fileMenuRes);
  268.         if SkelMenu(fileMenu, @DoFileMenu, nil, true) then
  269.             ;
  270. { Set the following flags so they match the menu }
  271.         soundFlag := true;
  272.         plotFastFlag := true;
  273.     end;
  274.  
  275. { Hide gamewindow on suspend, so the user can get access to disk icons etc. }
  276.  
  277.     procedure DoSuspendResume (b: boolean);
  278.     begin
  279.         if b then
  280.             begin
  281.                 ShowWindow(gSAT.wind.port);
  282.                 SelectWindow(gSAT.wind.port);
  283.             end
  284.         else
  285.             HideWindow(gSAT.wind.port)
  286.     end;
  287.  
  288.     function DoEvt (e: eventRecord): boolean;
  289.     begin
  290.         if e.what = OSevt then
  291.             begin
  292.                 if BAND(BROTL(e.message, 8), $FF) = SuspendResumeMessage then
  293.                     DoSuspendResume(BAnd(e.message, 1) <> 0);
  294.                 DoEvt := true;
  295.             end
  296.         else
  297.             DoEvt := false;
  298.     end; (* end DoEvent *)
  299.  
  300. { -------------------------------------------------------------------- }
  301. {                                    Main                                }
  302. { -------------------------------------------------------------------- }
  303.  
  304.     var
  305.         gameArea: Rect;
  306.  
  307. begin
  308.     SkelInit(6, nil);                { initialize }
  309.  
  310. { Init all the different parts of the game. }
  311.  
  312.     SetUpMenus;                        { install menu handlers }
  313.  
  314.     SetRect(gameArea, 0, 0, 512, 342);
  315. {We use SATCustomInit to cover the full screen INCLUDING menu bar area!}
  316.     SATCustomInit(129, 128, gameArea, nil, nil, true, true, true, true, true);
  317. {SATInit(129, 128, 512, 322);    {PICTs 129 and 128, width 512, height 322.}
  318.     GameWindInit;    { Install the game window (SATwind) in TransSkel and show it. }
  319.     Loadsounds;        { Preload all sound resources }
  320.  
  321. { Call the init routines for all the sprite units (generally to preload faces)!}
  322. { This must be done after SATInit! }
  323.     InitEnemy;
  324.     InitPlayer;
  325.     InitMissile;
  326.     InitShot;
  327.  
  328. {$IFC UNDEFINED THINK_PASCAL}
  329.     qd.randSeed := TickCount;    { Set the randseed to something that is random enough. }
  330. {$ELSEC}
  331.     randSeed := TickCount;    { Set the randseed to something that is random enough. }
  332. {$ENDC}
  333.  
  334.     if 0 < SATSoundInitChannels(2) then
  335.         ; {Use 2 channels}
  336.  
  337.     SkelEventHook(@DoEvt); { Handle MultiFinder-events }
  338.  
  339.     SkelMain;                    { Loop 'til Quit selected }
  340.     SkelClobber;                { Clean up }
  341.     SATSoundShutUp;            { Terminate sounds, free the sound channel. }
  342. end.